/**
 * Copyright (c) 2009 Teoti Graphix, LLC See:
 *     http://tkarchitecture.teotigraphix.org
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 * 
 * @author Michael Schmalle mschmalle@teotigraphix.com
 */
package org.teotigraphix.tka.patterns.component
{

import flash.display.DisplayObjectContainer;
import flash.events.Event;
import flash.events.IEventDispatcher;

import org.teotigraphix.dx.core.ToolKitConstants;
import org.teotigraphix.dx.core.ToolKitHelper;
import org.teotigraphix.dx.core.ToolKitPhase;
import org.teotigraphix.dx.core.ToolKitUtil;
import org.teotigraphix.dx.event.BehaviorLayerEvent;
import org.teotigraphix.dx.event.ModelLayerEvent;
import org.teotigraphix.dx.interfaces.IActivate;
import org.teotigraphix.dx.interfaces.IBehaviorLayer;
import org.teotigraphix.dx.interfaces.IBehaviorLayerAware;
import org.teotigraphix.dx.interfaces.IComponentBehavior;
import org.teotigraphix.dx.interfaces.IComponentBehaviorCore;
import org.teotigraphix.dx.interfaces.IComponentModel;
import org.teotigraphix.dx.interfaces.IComponentModelCore;
import org.teotigraphix.dx.interfaces.IComponentSkinCore;
import org.teotigraphix.dx.interfaces.ICoreBehaviorAware;
import org.teotigraphix.dx.interfaces.ICoreModelAware;
import org.teotigraphix.dx.interfaces.ICoreSkinAware;
import org.teotigraphix.dx.interfaces.IModelLayer;
import org.teotigraphix.dx.interfaces.IModelLayerAware;
import org.teotigraphix.dx.interfaces.ISkinLayer;
import org.teotigraphix.dx.interfaces.ISkinLayerAware;
import org.teotigraphix.dx.interfaces.IToolKitComponent;
import org.teotigraphix.dx.interfaces.IToolKitFactory;
import org.teotigraphix.dx.interfaces.IToolKitFactoryAware;
import org.teotigraphix.dx.patterns.manager.ToolKitManager;
import org.teotigraphix.tka.interfaces.ISparkSkinAware;

import spark.components.supportClasses.Skin;
import spark.components.supportClasses.SkinnableComponent;

//--------------------------------------
//  IconFile
//--------------------------------------

//[IconFile("ToolKitComponent.png")]

//--------------------------------------
//  Events
//--------------------------------------

/**
 * @eventType org.teotigraphix.dx.event.ComponentLayerEvent.LAYER_ACTIVATE
 */
[Event(name="layerActivate",type="org.teotigraphix.dx.event.ComponentLayerEvent")]

/**
 * @eventType org.teotigraphix.dx.event.ComponentLayerEvent.LAYER_DEACTIVATE
 */
[Event(name="layerDeactivate",type="org.teotigraphix.dx.event.ComponentLayerEvent")]

/**
 * @eventType org.teotigraphix.dx.event.ComponentLayerEvent.LAYER_DEACTIVATE
 */
[Event(name="skinAdd",type="org.teotigraphix.dx.event.SkinEvent")]

/**
 * @eventType org.teotigraphix.dx.event.ComponentLayerEvent.LAYER_DEACTIVATE
 */
[Event(name="skinRemove",type="org.teotigraphix.dx.event.SkinEvent")]

/**
 * @eventType org.teotigraphix.dx.event.BehaviorLayerEvent.BEHAVIOR_ADD
 */
[Event(name="behaviorAdd",type="org.teotigraphix.dx.event.BehaviorLayerEvent")]

/**
 * @eventType org.teotigraphix.dx.event.BehaviorLayerEvent.BEHAVIOR_REMOVE
 */
[Event(name="behaviorRemove",type="org.teotigraphix.dx.event.BehaviorLayerEvent")]

/**
 * @eventType org.teotigraphix.dx.event.ModelLayerEvent.MODEL_ADD
 */
[Event(name="modelAdd",type="org.teotigraphix.dx.event.ModelLayerEvent")]

/**
 * @eventType org.teotigraphix.dx.event.ModelLayerEvent.MODEL_REMOVE
 */
[Event(name="modelRemove",type="org.teotigraphix.dx.event.ModelLayerEvent")]

//--------------------------------------
//  Effects
//--------------------------------------

//[Effect(name="eventNameEffect",event="eventName")]

//--------------------------------------
//  Styles
//--------------------------------------

/**
 * Description.
 * 
 * <p></p>
 *  
 * @default
 * @mxml
 */
//[Style(name="styleProp",type="Number",inherit="no")]

//--------------------------------------
//  Excluded APIs
//--------------------------------------

//[Exclude(name="propName", kind="property")]

//--------------------------------------
//  Class
//--------------------------------------

/**
 * The <code>ToolKitComponent</code> is a skinnable component that implements the
 * <code>IToolKitComponent</code> api.
 * 
 * <p>TKArchitecture API:</p>
 * 
 * <p><strong>Toolkit</strong>:</p>
 * <ul>
 * <li><code>toolKitInitialized</code></li>
 * <li><code>startToolKit()</code></li>
 * <li><code>stopToolKit()</code></li>
 * </ul>
 * 
 * <p><strong>Cores</strong>:</p>
 * <ul>
 * <li><code>coreModel</code></li>
 * <li><code>coreSkin</code></li>
 * <li><code>coreBehavior</code></li>
 * </ul>
 * 
 * <p><strong>Layers</strong>:</p>
 * <ul>
 * <li><code>modelLayer</code></li>
 * <li><code>skinLayer</code></li>
 * <li><code>behaviorLayer</code></li>
 * </ul>
 * 
 * <p><strong>Collections</strong>:</p>
 * <ul>
 * <li><code>models</code></li>
 * <li><code>skins</code></li>
 * <li><code>behaviors</code></li>
 * </ul>
 * 
 * <p><strong>Factory</strong>:</p>
 * <ul>
 * <li><code>toolKitFactory</code></li>
 * </ul>
 * 
 * @copyright Teoti Graphix, LLC
 * @author Michael Schmalle
 * @date 12-04-08, 06-25-09
 * 
 * @mxml
 */
public class ToolKitComponent
	   extends SkinnableComponent
	   implements IToolKitComponent, IToolKitFactoryAware, ISparkSkinAware,
	   			  ICoreSkinAware, ICoreBehaviorAware, ICoreModelAware,
	   			  ISkinLayerAware, IBehaviorLayerAware, IModelLayerAware,
	   			  IActivate
{
	include "../../core/Version.as"
	
	//--------------------------------------------------------------------------
	//
	//  IActivate API :: Properties
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	//  isActive
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _isActive:Boolean = false;

	/**
	 * @copy org.teotigraphix.dx.interfaces.IActivate#isActive
	 * 
	 * @uses #commitComponent()
	 */
	public function get isActive():Boolean
	{
		return _isActive;
	}
	
	//--------------------------------------------------------------------------
	//
	//  IToolKitComponent API :: Properties
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	//  toolKitInitialized
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _toolKitInitialized:Boolean = false;
	
	[Bindable("toolKitInitializedChanged")]
	
	/**
	 * @copy org.teotigraphix.dx.interfaces.IToolKitComponent#toolKitInitialized
	 */
	public function get toolKitInitialized():Boolean
	{
		return _toolKitInitialized;
	}
	
	/**
	 * @private
	 */
	public function set toolKitInitialized(value:Boolean):void
	{
		_toolKitInitialized = value;
		dispatchEvent(new Event("toolKitInitializedChanged"));
	}

	//--------------------------------------------------------------------------
	//
	//  IToolKitFactoryAware API :: Properties
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	//  toolKitFactory
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _toolKitFactory:IToolKitFactory;
	
	[Bindable("toolKitFactoryChanged")]
	
	/**
	 * @copy org.teotigraphix.dx.interfaces.IToolKitFactoryAware#toolKitFactory
	 */
	public function get toolKitFactory():IToolKitFactory
	{
		return _toolKitFactory;
	}
	
	/**
	 * @private
	 */
	public function set toolKitFactory(value:IToolKitFactory):void
	{
		var old:IToolKitFactory = _toolKitFactory;
		_toolKitFactory = value;
		ToolKitUtil.dispatchChangeEvent(this, ToolKitConstants.TOOL_KIT_FACTORY, old, value);
	}
	
	//--------------------------------------------------------------------------
	//
	//  ICoreSkinAware API :: Properties
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	//  coreSkin
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _coreSkin:IComponentSkinCore;
	
	[Bindable("coreSkinChanged")]
	
	/**
	 * @copy org.teotigraphix.tka.interfaces.ICoreSkinAware#coreSkin
	 */
	public function get coreSkin():IComponentSkinCore
	{
		return _coreSkin;
	}
	
	/**
	 * @private
	 */
	public function set coreSkin(value:IComponentSkinCore):void
	{
		var old:IComponentSkinCore = _coreSkin;
		_coreSkin = value;
		ToolKitUtil.dispatchChangeEvent(this, ToolKitConstants.CORE_SKIN, old, value);
	}

	//--------------------------------------------------------------------------
	//
	//  ICoreBehaviorAware API :: Properties
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	//  coreBehavior
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _coreBehavior:IComponentBehaviorCore;
	
	[Bindable("coreBehaviorChanged")]
	
	/**
	 * @copy org.teotigraphix.tka.interfaces.ICoreBehaviorAware#coreBehavior
	 */
	public function get coreBehavior():IComponentBehaviorCore
	{
		return _coreBehavior;
	}
	
	/**
	 * @private
	 */
	public function set coreBehavior(value:IComponentBehaviorCore):void
	{
		var old:IComponentBehaviorCore = _coreBehavior;
		_coreBehavior = value;
		ToolKitUtil.dispatchChangeEvent(this, ToolKitConstants.CORE_BEHAVIOR, old, value);
	}

	//--------------------------------------------------------------------------
	//
	//  ICoreServiceAware API :: Properties
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	//  coreModel
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _coreModel:IComponentModelCore;
	
	[Bindable("coreModelChanged")]
	
	/**
	 * @copy org.teotigraphix.tka.interfaces.ICoreServiceAware#coreModel
	 */
	public function get coreModel():IComponentModelCore
	{
		return _coreModel;
	}
	
	/**
	 * @private
	 */
	public function set coreModel(value:IComponentModelCore):void
	{
		var old:IComponentModelCore = _coreModel;
		_coreModel = value;
		ToolKitUtil.dispatchChangeEvent(this, ToolKitConstants.CORE_MODEL, old, value);
	}
	
	//--------------------------------------------------------------------------
	//
	//  ISkinLayerAware API :: Properties
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	//  skinLayer
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _skinLayer:ISkinLayer;
	
	[StyleBinding]
	[Bindable("skinLayerChanged")]
	[Inspectable(category="Skin")]
	
	/**
	 * @copy org.teotigraphix.tka.interfaces.ISkinLayerAware#skinLayer
	 */
	public function get skinLayer():ISkinLayer
	{
		return _skinLayer;
	}
	
	/**
	 * @private
	 */	
	public function set skinLayer(value:ISkinLayer):void
	{
		var old:ISkinLayer = _skinLayer;
		_skinLayer = value;
		ToolKitUtil.dispatchChangeEvent(this, ToolKitConstants.SKIN_LAYER, _skinLayer, value);
	}
	
	//--------------------------------------------------------------------------
	//
	//  IBehaviorLayerAware API :: Properties
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	//  behaviorLayer
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _behaviorLayer:IBehaviorLayer;
	
	[StyleBinding]
	[Bindable("behaviorLayerChanged")] //
	[Inspectable(category="Behavior")]
	
	/**
	 * @copy org.teotigraphix.tka.interfaces.IBehaviorLayerAware#behaviorLayer
	 */
	public function get behaviorLayer():IBehaviorLayer
	{
		return _behaviorLayer;
	}
	
	/**
	 * @private
	 */	
	public function set behaviorLayer(value:IBehaviorLayer):void
	{
		var old:IBehaviorLayer = _behaviorLayer;
		_behaviorLayer = value;
		ToolKitUtil.dispatchChangeEvent(this, ToolKitConstants.BEHAVIOR_LAYER, old, value);
	}
	
	//----------------------------------
	//  behaviors
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _behaviors:Array;
	
	[Bindable("behaviorsChanged")]
	[ArrayElementType("org.teotigraphix.tka.interfaces.IComponentBehavior")]
	
	/**
	 * @copy org.teotigraphix.tka.interfaces.IBehaviorLayerAware#behaviors
	 */
	public function get behaviors():Array
	{
		return _behaviors;
	}
	
	/**
	 * @private
	 */	
	public function set behaviors(value:Array):void
	{
		var old:Array = _behaviors;
		_behaviors = value;
		ToolKitUtil.dispatchChangeEvent(this, ToolKitConstants.BEHAVIORS, old, value);
	}
	
	//--------------------------------------------------------------------------
	//
	//  IServiceLayerAware API :: Properties
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	//  modelLayer
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _modelLayer:IModelLayer;
	
	[StyleBinding]
	[Bindable("serviceLayerChanged")]
	[Inspectable(category="Service")]
	
	/**
	 * @copy org.teotigraphix.tka.interfaces.IServiceLayerAware#serviceLayer
	 */
	public function get modelLayer():IModelLayer
	{
		return _modelLayer;
	}
	
	/**
	 * @private
	 */	
	public function set modelLayer(value:IModelLayer):void
	{
		var old:IModelLayer = _modelLayer;
		_modelLayer = value;
		ToolKitUtil.dispatchChangeEvent(this, ToolKitConstants.MODEL_LAYER, old, value);
	}
	
	//----------------------------------
	//  models
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _models:Array;
	
	[Bindable("modelssChanged")]
	[ArrayElementType("org.teotigraphix.tka.interfaces.IComponentModel")]
	
	/**
	 * @copy org.teotigraphix.tka.interfaces.IModelLayerAware#models
	 */
	public function get models():Array
	{
		return _models;
	}
	
	/**
	 * @private
	 */	
	public function set models(value:Array):void
	{
		var old:Array = _models;
		_models = value;
		ToolKitUtil.dispatchChangeEvent(this, ToolKitConstants.MODELS, old, value);
	}
	
	//--------------------------------------------------------------------------
	//
	//  Constructor
	//
	//--------------------------------------------------------------------------

	/**
	 * Constructor.
	 */
	public function ToolKitComponent()
	{
		super();
		
		addEventListener(BehaviorLayerEvent.BEHAVIOR_ADD, behaviorAddHandler);
		addEventListener(BehaviorLayerEvent.BEHAVIOR_REMOVE, behaviorRemoveHandler);
		
		addEventListener(ModelLayerEvent.MODEL_ADD, modelAddHandler);
		addEventListener(ModelLayerEvent.MODEL_REMOVE, modelRemoveHandler);		
		
		ToolKitHelper.dispatchPhase(this, ToolKitPhase.CONSTRUCT);
	}
	
	//--------------------------------------------------------------------------
	//
	// Overridden Protected :: Methods
	//
	//--------------------------------------------------------------------------
	
	override public function initialize():void
	{
		ToolKitHelper.dispatchPhase(this, ToolKitPhase.INITIALIZE);
		super.initialize();
		ToolKitHelper.dispatchPhase(this, ToolKitPhase.INITIALIZE_COMPLETE);
	}
	
	/**
	 * @private
	 */
	override protected function createChildren():void
	{
		super.createChildren();
		ToolKitHelper.dispatchPhase(this, ToolKitPhase.CREATE_CHILDREN);
	}
	
	/**
	 * @private
	 */
	override protected function attachSkin():void
	{
		super.attachSkin();
		ToolKitHelper.dispatchPhase(this, ToolKitPhase.SKIN_ATTATCHMENT, skin);
	}
	
	/**
	 * @private
	 */
	override protected function detachSkin():void
	{
		var old:Skin = skin;
		super.detachSkin();
		ToolKitHelper.dispatchPhase(this, ToolKitPhase.SKIN_DETATCHMENT, old);
	}	
	
	/**
	 * @private
	 */
	override protected function commitProperties():void
	{
		super.commitProperties();
		ToolKitHelper.dispatchPhase(this, ToolKitPhase.PROPERTIES);
	}
	
	/**
	 * @private
	 */
	override protected function measure():void
	{
		super.measure();
		ToolKitHelper.dispatchPhase(this, ToolKitPhase.MEASURE);
	}
	
	/**
	 * @private
	 */
	override protected function updateDisplayList(unscaledWidth:Number,
												  unscaledHeight:Number):void
	{
		super.updateDisplayList(unscaledWidth, unscaledHeight);
		ToolKitHelper.dispatchPhase(
			this, ToolKitPhase.DISPLAY_LIST, 
			{width:unscaledWidth, height:unscaledHeight});
	}
	
	//--------------------------------------------------------------------------
	//
	//  Override Public :: Methods
	//
	//--------------------------------------------------------------------------
	
	/**
	 * @private
	 */
	override public function parentChanged(parent:DisplayObjectContainer):void
	{
		super.parentChanged(parent);
		ToolKitHelper.dispatchPhase(this, ToolKitPhase.PARENT_CHANGE, parent);
	}
	
	/**
	 * @private
	 */
	override public function styleChanged(styleProp:String):void
	{
		super.styleChanged(styleProp);
		ToolKitHelper.dispatchPhase(this, ToolKitPhase.STYLE_CHANGE, styleProp);
	}

	/**
	 * This gets called after constructor but before createChildren(),
	 * meaning right after addChild() is called on the component.
	 */
	override public function stylesInitialized():void
	{
		super.stylesInitialized()
		ToolKitHelper.dispatchPhase(this, ToolKitPhase.STYLE_INITIALIZE);
	}
	
	//--------------------------------------------------------------------------
	//
	//  IToolKitComponent API :: Methods
	//
	//--------------------------------------------------------------------------
	
	/**
	 * @copy org.teotigraphix.tka.interfaces.IToolKitComponent#initializeToolKit()
	 */
	public function initializeToolKit():void
	{
	}
	
	/**
	 * @copy org.teotigraphix.tka.interfaces.IToolKitComponent#startToolKit()
	 */
	public function startToolKit():void
	{
	}
	
	/**
	 * @copy org.teotigraphix.tka.interfaces.IToolKitComponent#stopToolKit()
	 */
	public function stopToolKit():void
	{
	}
	
	//--------------------------------------------------------------------------
	//
	//  ISkinAware API :: Methods
	//
	//--------------------------------------------------------------------------
	
	/**
	 * @copy org.teotigraphix.tka.interfaces.ISkinAware#invalidateSkin()
	 */
	public function invalidateSkin():void
	{
		invalidateSkinState();
	}
	
	//--------------------------------------------------------------------------
	//
	//  IActivate API :: Methods
	//
	//--------------------------------------------------------------------------
	
	/**
	 * @copy org.teotigraphix.dx.interfaces.IActivate#activate()
	 */
	public function activate(host:IEventDispatcher):void
	{
		_isActive = true;
	}
	
	/**
	 * @copy org.teotigraphix.dx.interfaces.IActivate#activate()
	 */
	public function deactivate(host:IEventDispatcher):void
	{
		_isActive = false;
	}
	
	//--------------------------------------------------------------------------
	//
	//  Overridden Public Unit Test :: Utility
	//
	//--------------------------------------------------------------------------	
	
	/**
	 * @private
	 */
	override public function validateProperties():void
	{
		super.validateProperties();
		ToolKitManager.validateProperties(this);
	}
	
	/**
	 * @private
	 */
	override public function validateSize(recursive:Boolean = false):void
	{
		super.validateSize(recursive);
		ToolKitManager.validateSize(this);
	}	
	
	/**
	 * @private
	 */
	override public function validateDisplayList():void
	{
		super.validateDisplayList();
		ToolKitManager.validateDisplayList(this);
	}	
	
	//--------------------------------------------------------------------------
	//
	//  Behavior/Service :: Methods
	//
	//--------------------------------------------------------------------------	
	
	/**
	 * @private
	 */
	private function behaviorAddHandler(event:BehaviorLayerEvent):void
	{
		behaviorAdded(event.api, event.behavior);
	}
	
	/**
	 * @private
	 */
	private function behaviorRemoveHandler(event:BehaviorLayerEvent):void
	{
		behaviorRemoved(event.api, event.behavior);
	}	
	
	/**
	 * @private
	 */
	private function modelAddHandler(event:ModelLayerEvent):void
	{
		modelAdded(event.api, event.model);
	}
	
	/**
	 * @private
	 */
	private function modelRemoveHandler(event:ModelLayerEvent):void
	{
		modelRemoved(event.api, event.model);
	}
	
	/**
	 * Called when the <code>component.behaviorLayer</code> has it's
	 * <code>registerBehavior()</code> method executed.
	 * 
	 * @param api The Class api used to key the registered 
	 * <code>IComponentBehavior</code>.
	 * @param The registered <code>IComponentBehavior</code>.
	 */
	protected function behaviorAdded(api:Class, behavior:IComponentBehavior):void
	{
	}
	
	/**
	 * Called when the <code>component.behaviorLayer</code> has it's
	 * <code>removeBehavior()</code> method executed.
	 * 
	 * @param api The Class api used to key the remove 
	 * <code>IComponentBehavior</code>.
	 * @param The removed <code>IComponentBehavior</code>.
	 */
	protected function behaviorRemoved(api:Class, behavior:IComponentBehavior):void
	{
	}
	
	/**
	 * Called when the <code>component.modelLayer</code> has it's
	 * <code>registerModel()</code> method executed.
	 * 
	 * @param api The Class api used to key the registered 
	 * <code>IComponentModel</code>.
	 * @param model The registered <code>IComponentModel</code>.
	 */
	protected function modelAdded(api:Class, model:IComponentModel):void
	{
	}
	
	/**
	 * Called when the <code>component.modelLayer</code> has it's
	 * <code>removeModel()</code> method executed.
	 * 
	 * @param api The Class api used to key the remove 
	 * <code>IComponentModel</code>.
	 * @param model The removed <code>IComponentModel</code>.
	 */
	protected function modelRemoved(api:Class, model:IComponentModel):void
	{
	}
}
}